package cn.geewallet.util;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.TimeZone;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import cn.geewallet.Geewallet;
import cn.geewallet.exception.GeewalletClientException;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;

/**
 * 签名工具类
 */
public class GeewalletKit {

    private static String encodingCharset = "UTF-8";

    private static final Logger log = LoggerFactory.getLogger(GeewalletKit.class);

    public static String getISO8601Timestamp() {
        Date date = new Date();
        TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
        // TimeZone tz = TimeZone.getTimeZone("GMT-01");
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'+08:00'");
        df.setTimeZone(tz);
        String nowAsISO = df.format(date);
        return nowAsISO;
    }

    public static String packaging(JSONObject paramJson, JSONObject bizParamJson, String servicePath, String reqTime)
        throws GeewalletClientException {
        try {
            RSAUtils rsaUtils = RSAUtils.getInstance(Geewallet.clientPrivateKey, Geewallet.geewalletPublicKey);
            String key = AESUtils.generateAesKey();
            String jsonEnc = AESUtils.encryptData(bizParamJson.toJSONString(), key);
            String bkey = rsaUtils.encryptRSA(key);
            paramJson.put("keyEnc", bkey); // 加密的key
            paramJson.put("jsonEnc", jsonEnc); // 加密的报文
            String signStr =
                StringUtils.joinWith(StrPool.DOT, servicePath, Geewallet.clientId, reqTime, paramJson.toJSONString());
            log.info("签名内容[{}]", signStr);
            String sign = rsaUtils.signRSA(signStr, CharsetUtil.UTF_8);
            return sign;
        } catch (Exception e) {
            log.error("组装geecard请求异常", e);
            throw new GeewalletClientException("PACKAGING_ERROR", "组装渠道参数错误", e);
        }
    }

    public static JSONObject checkReturn(HttpResponse httpResponse, String servicePath)
        throws GeewalletClientException {
        return checkReturn(httpResponse, servicePath, false);
    }

    public static JSONObject checkReturn(HttpResponse httpResponse, String servicePath, boolean isFileUpService)
        throws GeewalletClientException {
        String resStr = httpResponse.body();
        if (StrUtil.isBlank(resStr)) {
            throw new GeewalletClientException("GW_RETUEN_BLANK", "调用渠道返回信息为空");
        }
        JSONObject resJsonObject = null;
        try {
            resJsonObject = JSON.parseObject(resStr);
        } catch (Exception e) {
            log.error(String.format("返回结果不是json无法处理[%s]", resStr), e);
            throw new GeewalletClientException("GW_RETUEN_NO_JSON", "渠道返回格式不正确");
        }

        // 错误信息直接返回
        if (StrUtil.isNotBlank(resJsonObject.getJSONObject("result").getString("errorCode"))
            || StrUtil.isNotBlank(resJsonObject.getJSONObject("result").getString("errorMsg"))) {
            log.error("渠道返回失败：{}", resStr);
            throw new GeewalletClientException("CHANNEL_RESLUT_FAI",
                resJsonObject.getJSONObject("result").getString("errorMsg"));
        }

        // RSA验签
        try {
            RSAUtils rsaUtils = RSAUtils.getInstance(Geewallet.clientPrivateKey, Geewallet.geewalletPublicKey);
            String vaStr = StringUtils.joinWith(StrPool.DOT, servicePath, Geewallet.clientId,
                httpResponse.header("Response-Time"), resJsonObject.toJSONString());
            if (!rsaUtils.verifyRSA(vaStr, httpResponse.header("Signature"), CharsetUtil.UTF_8)) {
                log.error(String.format("验证渠道签名失败[%s]", vaStr));
                throw new GeewalletClientException("CHANNEL_RESLUT_UNKONW", "验证渠道签名失败");
            }
            if (resJsonObject.getJSONObject("result").getString("resultState").equals("S")) {
                if (!isFileUpService) {
                    String key = rsaUtils.decryptRSA(resJsonObject.getJSONObject("data").getString("keyEnc"));
                    JSONObject dataJson = JSON.parseObject(
                        AESUtils.decryptData(resJsonObject.getJSONObject("data").getString("jsonEnc"), key));
                    log.info("渠道返回[{}]", dataJson);
                    return dataJson;
                } else {
                    log.info("上传文件渠道返回[{}]", resJsonObject);
                    return resJsonObject;
                }
            } else {
                throw new GeewalletClientException("CHANNEL_RESLUT_FAIL",
                    resJsonObject.getJSONObject("result").getString("errorCode") + "|"
                        + resJsonObject.getJSONObject("result").getString("errorMsg"));
            }
        } catch (Exception e) {
            log.error(String.format("处理返回结果异常[%s]", resStr), e);
            throw new GeewalletClientException("CHANNEL_RESLUT_UNKONW", "处理返回结果异常");
        }
    }

    public static HttpRequest setHeader(HttpRequest request, String sign, String reqTime, String clientId) {
        return request.header(Header.CONTENT_TYPE.getValue(), ContentType.JSON.getValue())
            .header("Version", Geewallet.VERSION).header("Request-Time", reqTime)
            .header("Sign-Type", Geewallet.DEFAULT_SIGN_TYPE).header("Request-Id", UUID.fastUUID().toString())
            .header("Signature", sign).header("Client-Id", clientId);
    }

    public static HttpRequest setHeaderV100(HttpRequest request, String sign, String reqTime, String clientId) {
        return request.header(Header.CONTENT_TYPE.getValue(), ContentType.JSON.getValue())
            .header("Version", Geewallet.VERSION_100).header("Request-Time", reqTime)
            .header("Sign-Type", Geewallet.DEFAULT_SIGN_TYPE).header("Signature", sign).header("Client-Id", clientId);
    }

    public static HttpRequest setFileUploadHeaderV100(HttpRequest request, String sign, String reqTime,
        String clientId) {
        return request.header(Header.CONTENT_TYPE.getValue(), ContentType.JSON.getValue())
            .header("Version", Geewallet.VERSION).header("Request-Time", reqTime)
            .header("Request-Id", UUID.fastUUID().toString())
            .header("Sign-Type", Geewallet.DEFAULT_SIGN_TYPE).header("Client-Id", clientId);
    }

    public static String generateRandomString(int length) {
        String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuilder sb = new StringBuilder(length);
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            sb.append(characters.charAt(random.nextInt(characters.length())));
        }
        return sb.toString();
    }

}